package com.vueblog.webapi.exception;

import com.vueblog.webapi.enums.ResponseEnum;
import com.vueblog.webapi.response.BaseResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.BindingException;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.net.ConnectException;
import java.sql.SQLException;
import java.util.HashSet;

/**
 * <p>
 * 全局异常
 * </p>
 *
 * @author intest
 * @since 2019-07-22
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UnauthorizedException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public void unauthorizedException(ShiroException e) {
        if (log.isTraceEnabled()) {
            log.trace("捕获Shiro授权异常", e);
        }
    }

    @ExceptionHandler(AuthenticationException.class)
    @ResponseBody
    public BaseResponse shiroException() {
        return new BaseResponse(ResponseEnum.LOGIN_PASSWORD_ERROR);
    }

    /**
     * 自定义的异常出来
     * @param exception
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public BaseResponse handleBusinessException(BusinessException exception) {
        return new BaseResponse(exception.getCode(), exception.getMsg());
    }

    /**
     * 参数错误异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public BaseResponse handleMissingServletRequestParameterException() {
        return new BaseResponse(ResponseEnum.BAD_REQUEST);
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public BaseResponse handleException(Exception e) {
        log.error("系统错误信息：", e);
        if (e instanceof NoHandlerFoundException) {
            //404错误异常捕获
            return new BaseResponse(ResponseEnum.NOT_FOUND);
        } else if (e instanceof BindException) {
            //请求参数类型错误异常捕获
            return new BaseResponse(ResponseEnum.BAD_REQUEST);
        } else if (e instanceof BindingException) {
            //mybatis未绑定异常捕获
            return new BaseResponse(ResponseEnum.BOUND_STATEMENT_NOT_FOUNT);
        } else if (e instanceof SQLException || e instanceof DataAccessException) {
            //数据库操作异常捕获
            if (checkErrorCode1267Exception(e)) {
                return new BaseResponse(ResponseEnum.UNSUPPORTED_CHARACTERS);
            } else {
                return new BaseResponse(ResponseEnum.DATABASE_ERROR);
            }
        } else if (e instanceof ConnectException) {
            //网络连接失败异常捕获
            return new BaseResponse(ResponseEnum.CONNECTION_ERROR);
        } else if (e instanceof HttpMessageNotReadableException) {
            //请求参数异常
            return new BaseResponse(ResponseEnum.BAD_REQUEST);
        } else {
            //其它异常捕获
            return new BaseResponse(ResponseEnum.SYSTEM_ERROR);
        }
    }

    private boolean checkErrorCode1267Exception(Throwable e) {
        HashSet<Integer> codes = new HashSet<>();
        codes.add(1267);
        codes.add(1366);

        if (e instanceof SQLException && codes.contains(((SQLException)e).getErrorCode())) {
            return true;
        }
        if (e != null) {
            return checkErrorCode1267Exception(e.getCause());
        }
        return false;
    }
}
